#ifndef QUEUE_THREADPOOL_H
#define QUEUE_THREADPOOL_H

#include <thread>
#include <vector>
#include <queue>
#include <functional>
#include <mutex>
#include <condition_variable>
#include <future>

class ThreadPool {
public:
    using TaskType = std::function<void()>;
    explicit ThreadPool(unsigned n = std::thread::hardware_concurrency()) {
        //构造线程池

        //设置线程数目
        unsigned thread_num = std::thread::hardware_concurrency();
        if (thread_num == 0) thread_num = 4;
        if (n == 0) n = thread_num;
        if (n > thread_num * 2) n = thread_num * 2;

        //创建线程
        for (unsigned i = 0; i < n; ++i) {
            threads_.emplace_back([this]() {
                threadFunc();
            });
        }
    }

    template<typename T>
    auto addTask(T func) -> std::future<decltype(func())> {
        //添加任务
        using RetType = decltype(func());
        auto task = std::make_shared<std::packaged_task<RetType()>>(std::move(func));
        {
            std::lock_guard lk(mtx_);
            tasks_.emplace([task]() {
                (*task)();
            });
        }
        cond_.notify_one();
        return task->get_future();
    }

    ~ThreadPool() noexcept {
        //回收线程资源
        {
            std::lock_guard lk(mtx_);
            isStop_ = true;
        }
        cond_.notify_all();
        for (auto&& t : threads_) {
            t.join();
        }
    }
private:
    void threadFunc() {
        //线程池中每个线程运行的方法
        while (true) {
            TaskType task;
            {
                std::unique_lock lk(mtx_);
                cond_.wait(lk, [this](){
                    return isStop_ || !tasks_.empty();
                });
                if (isStop_ && tasks_.empty()) break;
                task = std::move(tasks_.front());
                tasks_.pop();
            }
            task();
        }
    }

    std::vector<std::thread> threads_;  //线程
    std::queue<TaskType> tasks_;    //任务队列， 互斥访问
    bool isStop_ = false;           //停止标志
    std::mutex mtx_;                //互斥锁
    std::condition_variable cond_;  //条件变量
};

#endif //QUEUE_THREADPOOL_H